home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Reference Guide / C-C++ Interactive Reference Guide.iso / c_ref / csource5 / 305_01 / emandel.c < prev    next >
Text File  |  1990-02-14  |  51KB  |  2,202 lines

  1. /*
  2. TITLE:        EMANDEL.C;
  3. DATE:        7/2/88;
  4. DESCRIPTION:    "HGA Mandelbrot explorer.";
  5. VERSION:    1.09;
  6. KEYWORDS:    Mandelbrot;
  7. FILENAME:    EMANDEL.C;
  8. WARNINGS:    "Requires HGA & Hard disk. 640K recommended. Very slow without FPU.";
  9. SEE-ALSO:    MANDEL.DOC, EMDISPLAY.C EMDISPLAY.EXE, EMANDEL.EXE, EJULIA.EXE;
  10. SYSTEM:        MS-DOS;
  11. COMPILERS:    Aztec;
  12. AUTHORS:    Dan Schechter;
  13.  */
  14.  
  15. /* 
  16. This program is copyright 1988, 1989 by Dan Schechter.
  17. You may copy and distribute it only on a not-for-profit basis.
  18. You may modify it providing that you give attribution to the original author
  19. and document your modifications and distribute the modified version
  20. only on a not-for-profit basis.
  21.  
  22.  
  23. I provide this source code mainly for informational purposes. 
  24. However, if you do wish to try to compile it, the following command lines
  25. should work, if you have the Aztec C-86 compiler, version 4.10b.
  26. The first line below compiles EMANDEL.EXE for a PC-AT with an 80287 FPU.
  27. The next line compiles EJULIA.EXE for a PC-AT with an 80287 FPU.
  28. The next line compiles EMANDEL.EXE for any PC, XT or AT with or without an 80287 FPU.
  29. The last line compiles EJULIA.EXE for any PC, XT or AT with or without an 80287 FPU.
  30. The first two use the +ef switch which make the compiler generate in-line
  31. calls directly to the 80287. The second two use the sensing library.
  32. Thus the second two will generate programs that run on any PC, with or
  33. without an FPU, and will use the FPU if it is present; but the first two 
  34. will generate programs that run faster because they do not use library 
  35. calls for math.
  36.  
  37. c +l +2 +ef -n -lm87 -z3000 -dNUMLEVELS=301 emandel.c
  38. c +l +2 +ef -n -lm87 -z3000 -o ejulia -dNUMLEVELS=301 -dJULIA emandel.c
  39. c +l -n -lm87s -z3000 -dNUMLEVELS=301 emandel.c
  40. c +l -n -lm87s -z3000 -o ejulia -dNUMLEVELS=301 -dJULIA emandel.c
  41.  */
  42.  
  43. #define VERSION "1.09"
  44. #define DATE "7/2/88"
  45.  
  46. char *version = "Ver. "VERSION"-c "DATE;
  47.  
  48. /* NOTES -->     
  49.     
  50.     Exit codes:
  51.         0 No errors. Normal program termination.
  52.         1 Unrecognized command line option.
  53.         2 Wrong number of command line parameters.
  54.         3 Insufficient RAM to allocate PDATA array.
  55.         4 Insufficient disk space for .PIK file.
  56.         5 Can't open file named on command line.
  57.         6 Wrong program - Emandel/Ejulia.
  58.         7 xlimit or ylimit larger than allocated memory space.
  59.         8 height or xwidth larger than P_DATA_SIZE or P_DATA_NUM.
  60.           (7 and 8 should never happen. They would be software bugs.)
  61.         9 No RAM for virtscreen.
  62.         10 Invalid filename on command line.
  63.         99 No errors. Normal program termination. 
  64.            User requested non-zero exit code.
  65.  
  66.  */
  67. #include <stdio.h>
  68. #include <math.h>
  69. #include <string.h>
  70. #include <fcntl.h>
  71.  
  72. void    setmode(int), writedot(int,int), uppername(char *), del(char *s),
  73.     cleardot(unsigned char *,int,int), mybatname(char *,char *), exitt(int),
  74.     help(int), showlevels(int *,int *), flash(void), _s_p_l(int),
  75.     load(char *), myjpname(char *), writejp(double,double), virtto0(int),
  76.     reverse(void), clearscreen(int), 
  77.     telldouble(int,int,double,double,int,int),
  78.     revdot(int,int), sleep(int), soundoff(int), thresh_view(void), 
  79.     writepict(void), getthresh(int *,int *), grid(void), countfree(void), 
  80.     virt_write(char *), redraw(int *,int *,int,int), stripz(char *s),
  81.     writebyte(int,int,int), lognew(int), parsename(char *), mem_full(int),
  82.     revcross(int,int), mypctname(char *), mynewname(void), ng_help(int), 
  83.     sw_scr(void), g_putc(int), newdrive(int), parsepath(char *),
  84.     makebat(double,double,double,double,char *,int), g1_write(char *),
  85.     blink(int,int,unsigned char *), restore(int *,int *), k_timer(int),
  86.     g_write(char *), g_putch(int,int,int,unsigned char *), eratline(void);
  87. int    tpr(int), inkey(void), levc(int), levtonum(int), getdata(int,int),
  88.     auto_levels(int *,int *), newpath(char *), options(int), save(void),
  89.     blink_getc(int,int,unsigned char *), _getth(int,int), 
  90.     g_getreply(char *), calculate(void), hc_calculate(void);
  91. char     *timestring(int), *index(char *,int), *rindex(char *,int), 
  92.     *backe(char *,char *), *numtolev(int), *g_gets(char *,int,char *), 
  93.     *_katof_fill(char *, char *);
  94. long    diskfree(void), filesize(char *), clock(void), kt_(void);
  95. void    *malloc(), *abstoptr(long);
  96. double    dsqroot(double), atof(char *), atoi_d(char *);
  97.  
  98. #define strchr index
  99. #define strrchr rindex
  100.  
  101. #define _STRTODLEN_ 50    /* Maximum length of floating point strings. */
  102. #define NORMAL 0
  103. #define GRAPHICS 1
  104. #define INDEXPORT 0x3B4
  105. #define CONTROLPORT 0x3b8
  106. #define DATAPORT 0x3b5
  107. #define CONFIGPORT 0x3bf
  108. #define SCREEN_ON 8
  109. #define GRAPH 2
  110. #define TEXT 0x20
  111. #define SCREEN0 0xb0000l     /* Screen address. */
  112. #define SCREEN1 0xb8000l
  113.  
  114. #define PATHLEN 160            /* Maximum length of path strings. */
  115. #define NAMELEN 13
  116. #define BATCH_LENGTH 127    /* Longest allowable command line, for makebat() */
  117. #define P_DATA_NUM 672        /* MUST be divisible by 8 */
  118. #define P_DATA_SIZE 504        /* MUST be divisible by 8 */ /* or by 4? */
  119. #define AREA 338688.0        /* 672 * 504 as a double  */
  120. #define PIC_SIZE (xwidth8*height+P_DATA_NUM+160)
  121. #define HEADER_LENGTH 127l        /* Length of data file header. 
  122.                     Used to figure full file size. */
  123. #define eratline() g_write("\r");
  124. #define G_DELAY 100            /* Constant for sleep() in setmode() */
  125. #define B_DELAY 1            /* Constant for sleep() in blink() */
  126. #define S_COUNT 25            /* Constant for soundoff() */
  127. #define FLASH_DELAY 200            /* Constant for sleep() in flash() */
  128. #define FONTADDR 0xffa6e        /* ROM font address. */
  129. #define STRIPZ_C '$'            /* Used by stripz(). */
  130. #define ASPECT .75
  131.  
  132. #ifndef NUMLEVELS    
  133. #define NUMLEVELS 201    /* Beware of setting NUMLEVELS so high that stack space is exhausted */
  134. #endif
  135.  
  136. #ifdef JULIA
  137. #define ARGNUM 6
  138. #else
  139. #define ARGNUM 4
  140. #endif
  141.  
  142. /* For emulating systems with less than 640K of ram, HOGMEM allocates
  143. some memory just to tie it up. FREEBLOCKS reports the number of K of RAM
  144. not used by the program. These are for diagnistic purposes only. */
  145. #ifdef HOGMEM
  146. #ifndef FREEBLOCKS
  147. #define FREEBLOCKS
  148. #endif
  149. char *hog[512];
  150. int hogmem=HOGMEM;
  151. #endif
  152.  
  153. #ifdef FREEBLOCKS
  154. unsigned char *freep[512];
  155. int numfree;
  156. char *stackp;
  157. int stackcount;
  158. #endif
  159.  
  160. unsigned xwidth;
  161. unsigned height;
  162. unsigned virt_size;
  163. unsigned char *pdata[P_DATA_NUM];    /* The main data array. */
  164. unsigned char *screen0;            /* Pointer to screen memory. */
  165. unsigned char *screen1;
  166. unsigned char *virtscreen;        /* The virtual screen */
  167. unsigned char *font;            /* Pointer to ROM character font. */
  168. char scr_num;                /* Active screen number. */
  169. int g_th,g1_tv,g1_th;            /* Graphics text cursor coordinates. */
  170. long old_file_size;            /* Number of bytes in present .PIK file. */
  171. long full_file_size;            /* Total space required for .PIK file    */
  172. int groupsize;                /* Size of one disk group */
  173. long total_time;            /* Cumulative calculation time. */
  174. long this_time;                /* Calc time this session. */
  175. char ESC;                /* Immediate escape from g_gets() */
  176. char beep;                /* Beep when done if true. */
  177. char autoexit;                /* Exit when done if true. */
  178. char nz_ex;            /* Flag to force exit() to return non-zero. */
  179. char pathname[PATHLEN] ;
  180. char filename[NAMELEN] ;
  181. int drivenum;
  182. unsigned xwidth8;
  183. int ii,ylimit,xlimit,maxit=255;
  184. double rcorner,icorner,bottom,increment;
  185. double rjulia,ijulia;
  186. double wsize=1.0;                /* % of possible area. */
  187. double aspect=ASPECT;                /* ylimit/xlimit */
  188. char working[60];             /* String for -WORKING- message. */
  189.  
  190. int gdata[12] = { 
  191.     0x35, 0x2d, 0x2e, 0x7, 0x5b, 
  192.     0x2, 0x57, 0x57, 0x2, 0x3, 0x0, 0x0 };
  193. int tdata[12] = { 
  194.     0x61, 0x50, 0x52, 0xf, 0x19, 
  195.     0x6, 0x19, 0x19, 0x2, 0xd, 0xb, 0xc };
  196.  
  197. char *_help[2] = {
  198. #ifdef JULIA
  199. "Ejulia from Kittensoft. ",
  200. ".\n\nUsage:\nEJULIA <Lr> <Ti> <Bi> <rj> <ij> [/M<m>] [/A<asp>] [/S<s>] [/N<fn>] [/X] [/B<n>]\n\
  201. or:\nEJULIA <filename>\n"
  202. #else
  203. "Emandel from Kittensoft. ",
  204. ".\n\nUsage: EMANDEL <Lr> <Ti> <Bi> [/M<m>] [/S<s>] [/A<asp>] [/N<fn>] [/X] [/B<n>]\n\
  205.    or: EMANDEL <filename>\n"
  206. #endif
  207. };
  208.  
  209. char *cpyr = "Copyright (c) 1988, 1989 by Dan Schechter";
  210.  
  211. char *beg = "\
  212. This program is shareware. Please give copies to your friends.\n\
  213. If you find it enjoyable please register your copy by sending $20 to:\n\n\
  214. \040\040\040\040\057\134\137\057\134\t\t\tDan Schechter\n\
  215. \040\040\040\050\376\040\322\040\376\051\t\t\tRoute 1 Box 19\n\
  216. \360\360\360\360\040\304\312\304\040\360\360\360\360\t\t\tAmenia, North Dakota 58004\n\
  217. \040\040\040\040\040\042\042\042\n";
  218.  
  219. int main(n,arg)
  220. int n;
  221. char **arg;
  222. {
  223. #ifdef FREEBLOCKS
  224.     char stacktop,trash;
  225. #endif
  226.     int r,ex,i;
  227.     char fv,c,*wp;
  228.     long dfree;
  229.     double tsize;
  230.     
  231. #ifdef HOGMEM
  232.     char s[25];
  233.     
  234.     printf("hogmem? (%d) ",hogmem);
  235.     gets(s);
  236.     if (s[0]) hogmem=atoi(s);
  237.     for (i=0;i<hogmem;i++) hog[i]=malloc(1024);
  238. #endif
  239.     system("break off");
  240.     increment=1.0;
  241.     font=abstoptr(FONTADDR);
  242.     screen0=abstoptr(SCREEN0);
  243.     screen1=abstoptr(SCREEN1);
  244.     newdrive(-1);
  245.  
  246.     if (n==2) load(arg[1]);
  247.     
  248.     else {
  249.         mynewname();
  250.         while ((n>1)&&(arg[n-1][0]=='/')){
  251.             n--;
  252.             switch(tpr(arg[n][1])){
  253.                 case 'M': 
  254.                     maxit=atoi(arg[n]+2); 
  255.                     if (maxit>1023) maxit=1023;
  256.                     break;
  257.                 case 'N':
  258.                     parsename(arg[n]+2);
  259.                     break;
  260.                 case 'S':
  261.                     wsize=atof(arg[n]+2);
  262.                     if (wsize<0.05) wsize=0.05;
  263.                     if (wsize>1.0)  wsize=1.0;
  264.                     break;
  265.                 case 'A':
  266.                     aspect=atof(arg[n]+2);
  267.                     if ((aspect<.01)||(aspect>100))
  268.                         aspect=ASPECT;
  269.                     break;
  270.                 case 'B':
  271.                     beep= arg[n][2];
  272.             beep = ((beep>='0')&&(beep<='9')) ? beep-48 : 0 ;
  273.                     break;
  274.                 case 'X':
  275.                     autoexit=1;;
  276.                     break;
  277.                 default:
  278.             printf("\n*** Unregognized option: %s\n",arg[n]);
  279.                     ng_help(0);
  280.                     exitt(1);
  281.             }
  282.         }
  283.         if (n!=ARGNUM){
  284.              ng_help(1);
  285.             exitt(2);
  286.         }
  287.         
  288.         height=ylimit=P_DATA_SIZE;
  289.         xwidth=xlimit=P_DATA_NUM;
  290.         if (aspect > ASPECT) xwidth=xlimit= ylimit/aspect;
  291.         if (aspect < ASPECT) height=ylimit= xlimit*aspect;
  292.         tsize= ( (double)xlimit*(double)ylimit )/AREA;
  293.         if (wsize < tsize){
  294.             xwidth=xlimit = xlimit*dsqroot(wsize)/dsqroot(tsize);
  295.             height=ylimit = ylimit*dsqroot(wsize)/dsqroot(tsize);
  296.         }
  297.         else wsize=tsize;
  298.         while(height%4) height++;
  299.         while(xwidth%8) xwidth++;
  300.         if ((height>P_DATA_SIZE)||(xwidth>P_DATA_NUM)){
  301.             ng_help(4);
  302.             exitt(8);
  303.         }
  304.         rcorner=atof(arg[1]);
  305.         icorner=atof(arg[2]);
  306.         bottom=atof(arg[3]);
  307.         increment= (icorner - bottom)/ylimit;
  308.  
  309. #ifdef JULIA
  310.         rjulia=atof(arg[4]);
  311.         ijulia=atof(arg[5]);
  312. #endif
  313.         xwidth8=xwidth>>3;
  314.         virt_size= xwidth8*height;
  315.         if ((virtscreen=malloc(virt_size))==0){
  316.             ng_help(2);
  317.             exitt(9);
  318.         }
  319.         ex = (maxit>255)? height+(height>>2) : height ;
  320.         for(i=0;i<xwidth;i++){
  321.             pdata[i]=malloc(ex);
  322.             if (pdata[i]==0){
  323.                 mem_full(i);
  324.                 break;
  325.             }
  326.             memset(pdata[i],0,ex);
  327.         }
  328.         setmode(GRAPHICS);
  329.         clearscreen(0);
  330.         clearscreen(1);
  331.         i=0;
  332.     }
  333.     sprintf(working,"\rWorking on %s. Press ?? for help. ",filename);
  334.  
  335.     full_file_size = (maxit>255) ? height + (height>>2) : height;
  336.     full_file_size *= xwidth;
  337.     full_file_size += HEADER_LENGTH;
  338.     old_file_size= filesize(filename);
  339.     dfree=diskfree()+old_file_size;
  340.     if (old_file_size % groupsize) 
  341.         dfree += groupsize - (old_file_size % groupsize);
  342.     if (full_file_size > dfree){
  343.         setmode(NORMAL);
  344.         printf("\n*** Insufficient disk space for %ld byte data file.\n%ld\n",full_file_size,dfree);
  345.         for (i=0;i<xwidth;i++) free(pdata[i]);
  346.         free(virtscreen);
  347.         ng_help(0);
  348.         exitt(4);
  349.     }  
  350.     
  351. #ifdef FREEBLOCKS
  352.     countfree();
  353.     stackp = &stacktop;
  354.     g_write(" FREEBLOCKS reminder. Call threshview/redraw for stack check. ");
  355.     blink_getc(340,g_th,screen0);
  356. #endif 
  357.     
  358.     if ((xlimit>xwidth)||(ylimit>height)){
  359.         setmode(NORMAL);
  360.         printf("*** Limits error.");
  361.         printf("\nxl=%d pdn=%d yl=%d pds=%d",xlimit,xwidth,ylimit,height);
  362.         exitt(7);
  363.     }
  364.     
  365.     if ((autoexit)&&(!scr_num)) sw_scr();
  366. _kee:    k_timer(1);
  367.     ex = (maxit<=255) ? calculate() : hc_calculate() ;
  368.     k_timer(0);
  369.  
  370.     if (ex) g_write("\rCalculation halted. ");
  371.     else {
  372.         g_write("\rCalculation completed. ");
  373.         for(;beep;beep--) putchar(7);
  374.         if (autoexit){
  375.             if (scr_num) sw_scr();
  376.             if (save()){
  377.                 setmode(NORMAL);
  378. #ifdef JULIA
  379.                 printf("EJULIA from Kittensoft. %s.\n%s\n%s",version,cpyr,beg);
  380. #else
  381.                 printf("EMANDEL from Kittensoft. %s.\n%s\n%s",version,cpyr,beg);
  382. #endif
  383.                 exitt(0);
  384.             }
  385.             
  386.         }
  387.     }
  388.     for (fv=0;;){
  389.         r=blink_getc(340,g_th,screen0);
  390.         if (r==21) break;
  391.         if (r==3){
  392.             if (scr_num) { flash(); continue; }
  393.             if (!fv) {
  394.                 eratline();
  395.                 g_write(filename);
  396.                 g_write(" not saved. Exit? ");
  397.                 if ( g_getreply("YN")=='N' ) {
  398.                     g_write(" Well okay then... Calculation ");
  399.                     if (ex) g_write("halted. ");
  400.                     else g_write("completed. ");
  401.                     continue;
  402.                 }
  403.             }
  404.             for (i=xwidth;i;i--) free(pdata[i-1]);
  405.             free(virtscreen);
  406.             setmode (NORMAL);
  407. #ifdef JULIA
  408.             printf("EJULIA from Kittensoft. %s.\n%s\n%s",version,cpyr,beg);
  409. #else
  410.             printf("EMANDEL from Kittensoft. %s.\n%s\n%s",version,cpyr,beg);
  411. #endif
  412.             printf("\nCalc time: This session: %s ",timestring(1));
  413.             printf("Total: %s [Rem: ",timestring(2));
  414.             printf("%s] ",timestring(3));
  415.             
  416.             if (fv) printf("\n%s saved.\n",filename);
  417.             else printf("\n%s not saved.\n",filename);
  418.             
  419. #ifdef FREEBLOCKS
  420.             printf("\n\n%d free 1K blocks. Stackcount=%d",numfree,stackcount);
  421. #endif
  422.             if (nz_ex) exitt(99);
  423.             exitt(0);
  424.         }
  425.         switch (options(r)){
  426.             case 1: fv=1; break;
  427.             case 'w': 
  428.                 if (ex) g_write("\rCalculation halted. ");
  429.                 else g_write("\rCalculation completed. ");
  430.                 break;
  431.         }
  432.     }
  433.     if (ex) for (r=0;r<ylimit;r++) cleardot(screen0,r,ii);
  434.     goto _kee;
  435. }
  436.  
  437. void setmode(q)
  438. int q;
  439. {
  440.     int i;
  441.     
  442.     clearscreen(0);  
  443.     switch (q) {
  444.         case GRAPHICS:
  445.                 outportb(CONFIGPORT,3);
  446.                 outportb(CONTROLPORT,2);
  447.                 for(i=0;i<12;i++){
  448.                     outportb(INDEXPORT,i);
  449.                     outportb(DATAPORT,gdata[i]);
  450.                 }
  451.                 sleep(G_DELAY);
  452.                 outportb(CONTROLPORT,10);
  453.                 break;
  454.         case NORMAL:
  455.                 outportb(CONTROLPORT,0);
  456.                 for(i=0;i<12;i++){
  457.                     outportb(INDEXPORT,i);
  458.                     outportb(DATAPORT,tdata[i]);
  459.                 }
  460.                 sleep(G_DELAY);
  461.                 outportb(CONTROLPORT,40);
  462.                 outportb(CONFIGPORT,0);
  463.                 scr_clear();
  464.                 break;
  465.     }
  466. }
  467. void sw_scr()
  468. {
  469.     
  470.     scr_num^=128;
  471.     outportb(CONTROLPORT, 10 | scr_num);
  472. }
  473. void clearscreen(q)
  474. int q;
  475. {
  476.     if (q)  memset(screen1,0,(unsigned)32768); 
  477.     else {
  478.         memset(screen0,0,(unsigned)32768); 
  479.         memset(virtscreen,0,virt_size); 
  480.     }
  481. }
  482.  
  483. /* The following pair of functions will return a grossly wrong elapsed
  484. time if they span from a leap year into the following new year. */
  485.  
  486. void k_timer(q)
  487. int q;
  488. {
  489.     static long started;
  490.     long t;
  491.     
  492.     if (q) { started=kt_(); return; }
  493.     
  494.     t= kt_() - started;
  495.     this_time += t;
  496.     total_time += t;
  497. }
  498. long kt_()
  499. {
  500.     register long kt;
  501.     struct {
  502.         short sec;
  503.         short min;
  504.         short hour;
  505.         short trash1;
  506.         short trash2;
  507.         short year;
  508.         short trash3;
  509.         short yday;
  510.         short trash4;
  511.         short trash5;
  512.     } t;
  513.     
  514.     dostime(&t);
  515.     kt = (t.year - 88)*365+t.yday;
  516.     kt *= 24;
  517.     kt += t.hour;
  518.     kt *= 60;
  519.     kt += t.min;
  520.     kt *= 60;
  521.     return(kt + t.sec);
  522. }
  523. char *timestring(q)
  524. int q;
  525. {
  526.     static char str[15],elipsis[4]="...",zero[8]="0:00:00";
  527.     int m,s;
  528.     long t;
  529.     
  530.     if (!t) return zero;
  531.     switch (q) {
  532.         case 1: t=this_time;
  533.             break;
  534.         case 2: t=total_time;
  535.             break;
  536.         case 3: 
  537.             if (( (ii<<4) < xlimit)||( total_time < ii*3 )) 
  538.                 return elipsis;
  539.             t= (total_time/ii)*(xlimit-ii);
  540.             break;
  541.     }
  542.     s= t%60;
  543.     t /= 60;
  544.     sprintf(str,"%d:%02d:%02d",(int)t/60,(int)t%60,s);
  545.     return(str);
  546. }
  547. int inkey()
  548. {
  549.     
  550.     return(bdos(0x600,0xff,0));
  551. }
  552. void writedot(y,x)
  553. int x,y;
  554. {
  555.     unsigned char bit;
  556.     unsigned off;
  557.     
  558.     bit = 1<< (7-x%8);
  559.  
  560.     virtscreen[xwidth8*y + (x>>3)] |= bit;
  561.  
  562.     if (y%3==0) return;
  563.     y-=((y/3)+1);
  564.     off=(unsigned)( 0x2000 * (y&3) + 90*(y>>2) + (x>>3) );
  565.     
  566.     screen0[off] |= bit;
  567.     screen1[off] |= bit;
  568. }
  569. void revdot(y,x)
  570. int x,y;
  571. {
  572.     
  573.     if (y%3==0) return;
  574.     y-=((y/3)+1);
  575.     screen0[( 0x2000 * (y&3) + 90*(y>>2) + (x>>3) )] ^= (1<<(7-x%8));
  576. }
  577. void cleardot(seg,y,x)
  578. int x,y;
  579. unsigned char *seg;
  580. {
  581.     unsigned char bit;
  582.     
  583.     bit = (~(1<< (7-x%8)));
  584.     if (seg==screen0)
  585.         virtscreen[xwidth8*y + (x>>3)] &= (bit);
  586.  
  587.     if (y%3==0) return;
  588.     y-=((y/3)+1);
  589.     seg[( 0x2000 * (y&3) + 90*(y>>2) + (x>>3) )] &= (bit);
  590. }
  591. int save()
  592. {
  593.     int fd,num,sw;
  594.     long dfree;
  595.     char s[80];
  596.     
  597.     sw = (maxit>255) ? height+(height>>2) : height;
  598.     full_file_size = (long)sw * (long)ii + HEADER_LENGTH;
  599.     old_file_size=filesize(filename);
  600.  
  601.     dfree=diskfree()+old_file_size;
  602.     if (old_file_size % groupsize) 
  603.         dfree += groupsize - (old_file_size % groupsize);
  604.     if (full_file_size > dfree){
  605.         sprintf(s,"\rInsufficient disk space for %ld byte file. %ld. ",full_file_size,dfree);
  606.         g_write(s);
  607.         return(0);
  608.     }  
  609.     
  610.     if ((fd=open(filename,O_WRONLY|O_TRUNC))==-1){
  611.         g_write("\rCannot open pik file. ");
  612.         return(0);
  613.     }
  614.     g_write("Saving... ");
  615. #ifdef JULIA
  616.     write(fd,"J",1);
  617. #else
  618.     write(fd,"K",1);
  619. #endif
  620.     write(fd,(char *)&rcorner,8);
  621.     write(fd,(char *)&icorner,8);
  622.     write(fd,(char *)&xlimit,2);
  623.     write(fd,(char *)&ylimit,2);
  624.     write(fd,(char *)&xwidth,2);
  625.     write(fd,(char *)&height,2);
  626.     write(fd,(char *)&increment,8);
  627.     write(fd,(char *)&aspect,8);
  628.     write(fd,(char *)&wsize,8);
  629.     write(fd,(char *)&maxit,2);
  630.     write(fd,(char *)&ii,2);
  631.     write(fd,(char *)&bottom,8);
  632.     write(fd,(char *)&rjulia,8);
  633.     write(fd,(char *)&ijulia,8);
  634.     write(fd,(char *)&total_time,4);
  635.     write(fd,&beep,1);
  636.     write(fd,&autoexit,1);
  637.  
  638.     for (num=4;num;num--) write(fd,"KITTENSOFT ",11);
  639.  
  640.     for (num=0;num<ii;num++)
  641.         write(fd, pdata[num], sw);
  642.  
  643.     close(fd);
  644.     g_write(" Saved. ");
  645.     return(1);
  646. }
  647. void load(com_arg)
  648. char *com_arg;
  649. {
  650.     int fp,num,x,y,sw;
  651.     char buf[PATHLEN],*wp,q; 
  652.  
  653.     strcpy(buf,com_arg);
  654.     wp=strchr(buf,'.');
  655.     if (wp) strcpy(wp,".PIK");
  656.     else strcat(buf,".PIK");    /* Now buf should access the file. */
  657.     parsename(buf);            /* Now filename should contain
  658.                         name without path. */
  659.     
  660.     if ((fp=open(buf,O_RDONLY))==(-1)){
  661.         printf("\n*** Can't open file: %s\n",buf);
  662.         ng_help(0);
  663.         exitt(5);
  664.     }
  665.     if (( !read(fp,&q,1) ) ||
  666. #ifdef JULIA
  667.         (q!='J')) {
  668.             printf("\n*** %s not an Ejulia file.\n",buf);
  669.             ng_help(0);
  670.             exitt(6);
  671.     }
  672. #else
  673.         (q!='K')) {
  674.             printf("\n*** %s not an Emandel file.\n",buf);
  675.             ng_help(0);
  676.             exitt(6);
  677.     }
  678. #endif
  679.     read(fp,(char *)&rcorner,8);
  680.     read(fp,(char *)&icorner,8);
  681.     read(fp,(char *)&xlimit,2);
  682.     read(fp,(char *)&ylimit,2);
  683.     read(fp,(char *)&xwidth,2);
  684.     read(fp,(char *)&height,2);
  685.     read(fp,(char *)&increment,8);
  686.     read(fp,(char *)&aspect,8);
  687.     read(fp,(char *)&wsize,8);
  688.     read(fp,(char *)&maxit,2);
  689.     read(fp,(char *)&ii,2);
  690.     read(fp,(char *)&bottom,8);
  691.     read(fp,(char *)&rjulia,8);
  692.     read(fp,(char *)&ijulia,8);
  693.     read(fp,(char *)&total_time,4);
  694.     read(fp,&beep,1);
  695.     read(fp,&autoexit,1);
  696.     if (ii==xlimit) autoexit=0;
  697.     read(fp,buf,44);
  698.     
  699.     xwidth8=xwidth>>3;
  700.     virt_size= xwidth8*height;
  701.     if ((virtscreen=malloc(virt_size))==0){
  702.         ng_help(2);
  703.         exitt(9);
  704.     }
  705.     if (maxit>255) {
  706.         num=sw= height+(height>>2);
  707.     }
  708.     else sw=num = height;
  709.     
  710.     for(x=0;x<xwidth;x++){
  711.         pdata[x]=malloc(num);
  712.         if (pdata[x]==0){
  713.             mem_full(x);
  714.             if (ii>xwidth) ii=xwidth;
  715.             break;
  716.         }
  717.         memset(pdata[x],0,num);
  718.     }
  719.  
  720.     printf("\nReading data file %s ",filename);
  721.     for(num=0;num<ii;num++)
  722.         read(fp, pdata[num], sw);
  723.  
  724.     close(fp);
  725.     setmode(GRAPHICS);
  726.     clearscreen(0);
  727.     clearscreen(1);
  728.     
  729.     redraw(&x,&y,ii,0);
  730.     
  731. }
  732. void soundoff(q)
  733. int q;
  734. {
  735.     char buf[150];
  736.     int r,i;
  737.     
  738.     for(i=S_COUNT;i;i--){
  739.         if ((r=inkey())==0) sleep(B_DELAY);
  740.         else break;
  741.     }
  742.     if (!r){
  743.         sw_scr();
  744.         g1_write("\014\
  745. C  coordinates.\n\
  746. M  Maxit.\n\
  747. H  Horizontal position.\n\
  748. S  Frame size & ratio.\n\
  749. G  Magnification.\n\
  750. J  Julia point.\n\
  751. P  Drive:path.\n\
  752. I  Increment.\n\
  753. T  Time totals.\n\
  754. N  File name.\n\
  755. B  Beeper alarm.\n\
  756. X  Autoexit status.\n\
  757. %  Percent of frame completed.\n\
  758. ?  Help.\n\
  759. \n\
  760. Enter selection: ");
  761.     
  762.         r=blink_getc(g1_tv,g1_th,screen1);
  763.         sw_scr();
  764.         clearscreen(1);
  765.     }
  766.     buf[0]=0;
  767.     switch(tpr(r)){
  768.         case 'T':
  769.             sprintf(buf,"\002 Time: %s ",timestring(1));
  770.             sprintf(buf+strlen(buf),"* %s ",timestring(2));
  771.             sprintf(buf+strlen(buf),"[%s] ",timestring(3));
  772.             break;
  773.         case 'N':
  774.             sprintf(buf,"\002 fn: %s ",filename);
  775.             break;
  776.         case 'B':
  777.             sprintf(buf,"\002 Beep=%d ",beep);
  778.             break;
  779.         case 'X':
  780.             if (autoexit) sprintf(buf,"\002 aX:on ");
  781.             else sprintf(buf,"\002 aX:off ");
  782.             break;
  783.         case '5':
  784.         case '%':
  785.             sprintf(buf,"\002 %d%% ", (int)( (100*(long)ii)/xlimit ) );
  786.             break;
  787.         case 'S':
  788.             sprintf(buf,"\002 h=%d yl=%d w=%d xl=%d size=%g%c asp=%g%c ",height,ylimit,xwidth,xlimit,wsize,STRIPZ_C,aspect,STRIPZ_C);
  789.             break;
  790.         case 'C': 
  791.             sprintf(buf,"\002 Lr=%g%c Ti=%g%c Rr=%g%c Bi=%g%c ",rcorner,STRIPZ_C,icorner,STRIPZ_C,rcorner+(xlimit*increment),STRIPZ_C,bottom,STRIPZ_C);
  792.             break;  
  793. #ifdef JULIA
  794.         case 'J':
  795.             sprintf(buf,"\002 rj=%g%c ij=%g%c ",rjulia,STRIPZ_C,ijulia,STRIPZ_C);
  796.             break;
  797. #endif
  798.         case 'P':
  799.             lognew(0);
  800.             return;
  801.         case 'I': 
  802.             sprintf(buf,"\002 inc=%.3g ",increment);
  803.             break;
  804.         case 'G':
  805.             sprintf(buf,"\002 mag=%.3g ",2.5/(increment*height));
  806.             break;
  807.         case 'M': 
  808.             sprintf(buf,"\002 m=%d ",maxit);
  809.             break;
  810.         case 'H': 
  811.             sprintf(buf,"\002 hz=%d ",ii);
  812.             break;
  813.         case '/':
  814.         case '?':
  815.             help(q);
  816.             return;
  817.     }
  818.     stripz(buf);
  819.     g_write(buf);
  820. }
  821. void stripz(s0)
  822. char *s0;
  823. {
  824.     char *s;
  825.     
  826.     s=s0;
  827.     while( s=index(s,STRIPZ_C) ){
  828.         del(s--);
  829.         s=backe(s,s0);
  830.         if (!s) stripz(s0);
  831.         while( *s == '0' ) del(s--);
  832.     }
  833. }
  834. char *backe(s,s0)
  835. char *s,*s0;
  836. {
  837.     char *wp;
  838.     
  839.     for (wp=s; wp != s0 ; wp--)
  840.         switch(*wp){
  841.             case ' ': return((char *)0);
  842.             case '.': return(s);
  843.             case 'e': return(wp-1);
  844.     }
  845.     return((char *)0);
  846. }
  847.     
  848. void del(s)
  849. char *s;
  850. {
  851.     while (*s) (*s++) = (*(s+1));
  852. }
  853.  
  854. void telldouble(g,sn,d,e,i,j)
  855. double d,e;
  856. int i,j,g,sn;
  857. {
  858.     char buf[100];
  859.     int n;
  860.     
  861.     n= (maxit>255)? getdata(j,i) : pdata[i][j];
  862.     sprintf(buf,"\r%c-%d (?? for help.) r=%.15g i=%.15g itr=%d ",g,sn,d,e,n);
  863.     g_write(buf);
  864. }
  865. void revcross(j,i)
  866. int i,j;
  867. {
  868.     int w=ylimit,xw=xlimit;
  869.     
  870.     if (j%3==0) j++;
  871.     
  872.     while(xw) revdot(j,--xw);
  873.     while(w) revdot(--w,i);
  874. }
  875. void grid()
  876. {
  877.     int dir='5',c;
  878.     static int i,j,xoff,yoff,num=1,glide='s';
  879.  
  880.     *(unsigned char *)(abstoptr(0x417l))|=32;
  881.     revcross(j,i);
  882.     if (xoff||yoff) revcross(j+yoff,i+xoff);
  883.     telldouble(glide,num,rcorner+(i*increment),icorner-(j*increment),i,j); 
  884.     for(;;){
  885.         if ((c=tpr(inkey()))==27) break;
  886.         switch (c){
  887.             case ' ': eratline(); break;
  888.             case '/':
  889.             case '?': soundoff(1); dir='5'; break;
  890.             case 'L': lognew(1); dir='5'; break;
  891.             case '.': 
  892.                 glide ^= 20;
  893.                 g_putch(glide,340,0,screen0);
  894.                 break;
  895.             case '+': 
  896.             case '*': 
  897.             case '-': 
  898.             case 8:
  899.                 switch(c){
  900.                     case '+': num++; break;
  901.                     case '*': num += 5; break;
  902.                     case '-': if (num!=1) num--; break;
  903.                     case 8:   num=1; break;
  904.                 }
  905.                 telldouble(glide,num,rcorner+(i*increment),icorner-(j*increment),i,j); 
  906.                 break;
  907. #ifndef JULIA
  908.             case 10:  
  909.                 rjulia= rcorner+i*increment;
  910.                 ijulia= icorner-j*increment;
  911.                 makebat(-2.0, 2.0, -2.0, ASPECT, (char *)0, 'j'); 
  912.                 rjulia=ijulia=0.0;
  913.                 break;
  914. #endif
  915.             case '#': makebat(rcorner+(i*increment),icorner-(j*increment),icorner-((j+yoff)*increment),(double)yoff/(double)xoff,(char *)0,0); 
  916.                   break;
  917.             case 2:
  918.             case 19:
  919.             case 4:
  920.             case 21:
  921.             case 18:
  922.             case 12:
  923.             case '0':
  924.                 if (xoff||yoff) revcross(j+yoff,i+xoff);
  925.                 
  926.         /*S*/        if (c==19) { xoff-=4*num; yoff-=3*num; }
  927.         /*U*/        if (c==21) yoff-=num; 
  928.         /*L*/        if (c==12) xoff-=num; 
  929.         /*B*/        if ((c==2)&&(xoff+4*num+i<xlimit)&&(yoff+3*num+j<ylimit))
  930.                     { xoff+=4*num; yoff+=3*num; }
  931.         /*D*/        if ((c==4)&&(yoff+j+num<ylimit))  yoff+=num; 
  932.         /*R*/        if ((c==18)&&(xoff+i+num<xlimit)) xoff+=num; 
  933.         /*0*/        if (c=='0') xoff=yoff=0; 
  934.                 
  935.                 if (xoff<0) xoff=0;
  936.                 if (yoff<0) yoff=0;
  937.                 if (xoff||yoff) revcross(j+yoff,i+xoff);
  938.                 break;
  939.         }
  940.         if ((c>='1')&&(c<='9')) dir=c;
  941.         if (dir=='5') continue; 
  942.         
  943.         revcross(j,i);
  944.         if (xoff||yoff) revcross(j+yoff,i+xoff);
  945.         switch (dir) {
  946.             case '8': j-=num; break;
  947.             case '4': i-=num; break;
  948.             case '6': i+=num; break;
  949.             case '2': j+=num; break;
  950.             case '1': i-=num; j+=num; break;
  951.             case '3': i+=num; j+=num; break;
  952.             case '7': i-=num; j-=num; break;
  953.             case '9': i+=num; j-=num; break;
  954.         }
  955.         if (i<0) i=xlimit-xoff-1;
  956.         if (i+xoff>=xlimit) i=0;
  957.         if (j<0) j=ylimit-yoff-1;
  958.         if (j+yoff>=ylimit) j=0;
  959.         revcross(j,i);
  960.         if (xoff||yoff) revcross(j+yoff,i+xoff);
  961.         telldouble(glide,num,rcorner+(i*increment),icorner-(j*increment),i,j); 
  962.         if (glide=='s') dir='5';
  963.     }
  964.     if (xoff||yoff) revcross(j+yoff,i+xoff);
  965.     *(unsigned char *)(abstoptr(0x417l))^=32;
  966.     revcross(j,i);
  967. }
  968. void thresh_view()
  969. {
  970.     int bottom[NUMLEVELS],top[NUMLEVELS],level,th,cut=0;
  971.     int c;
  972.     char r[10];
  973.     unsigned char *tmpvirt;
  974.  
  975.     if (tmpvirt=malloc(virt_size))
  976.         memcpy(tmpvirt,virtscreen,virt_size);
  977.     th=g_th;
  978.     for (level=0;level<NUMLEVELS;level++) top[level]=(-1);
  979.  
  980.     for(;;){
  981.         g_write("\rTHRESHVIEW. Log, View, Grid, Write, Auto, Redraw, Mask, ?, or Cluster number: ");
  982.         g_gets(r,10,"LVGARM?/");
  983.         if (ESC) break;
  984.         switch (tpr(r[0])) {
  985.             case 'L': 
  986.                   lognew(1); 
  987.                   blink_getc(340,g_th,screen0);
  988.                   continue;
  989.             case 'V': showlevels(bottom,top); continue;
  990.             case 'G': grid(); continue;
  991.             case 'W': writepict(); continue;
  992.             case 'A': if (!auto_levels(bottom,top)) continue;
  993.             case 'R': redraw(top,bottom,ii,1); break;
  994.             case 'M': cut++; virtto0(cut%3); break;
  995.             case '/':
  996.             case '?': help(2); continue;
  997.         }
  998.         level=atoi(r);
  999.         if ((level==0)&&(r[0] != '0')) continue;
  1000.         if ((level<0)||(level>=NUMLEVELS)) continue;
  1001.         g_th=0;
  1002.         g_write(r);
  1003.         getthresh(bottom+level,top+level);
  1004.         if (ESC) continue;
  1005.         if (top[level]<bottom[level]) top[level]=(-1);
  1006.         redraw(top,bottom,ii,1);
  1007.     }
  1008. #ifdef FREEBLOCKS
  1009.     countfree();
  1010. #endif
  1011.  
  1012.     if (tmpvirt) {
  1013.         memcpy(virtscreen,tmpvirt,virt_size);
  1014.         virtto0(0);
  1015.         free(tmpvirt);
  1016.         g_th=th;
  1017.     }
  1018.     else {
  1019.         clearscreen(0);
  1020.         redraw(top,bottom,(ii==xlimit)?ii:ii+1,0);
  1021.         eratline();
  1022.     }
  1023. }
  1024. void virtto0(cut)
  1025. int cut;
  1026. {
  1027.     unsigned offv,off0,linev,line0;
  1028.     
  1029.     for(linev=line0=0;linev<ylimit;linev++){
  1030.         if ((linev%3)==cut) continue;
  1031.         offv= xwidth8*linev;
  1032.         off0= 0x2000 * (line0&3) + 90 * (line0>>2);
  1033.         memcpy(screen0+off0,virtscreen+offv,xwidth8);
  1034.         line0++;
  1035.     }
  1036. }
  1037. void getthresh(b,t)
  1038. int *b,*t;
  1039. {
  1040.     char buf[50];
  1041.     int c;
  1042.     
  1043.     if (*t==-1) sprintf(buf," Clear. New bottom? ");
  1044.     else sprintf(buf," bottom=%d top=%d  New bottom? ",*b,*t);
  1045.     g_write(buf);  
  1046.     c=*b;
  1047.     *b=_getth(*b,*t);
  1048.     if (ESC) return; 
  1049.     if (*b==-1) { *t=-1; return; }
  1050.     g_write("  New top? ");
  1051.     *t=_getth(*t,*b);
  1052.     if (ESC) { *b=c; return; }
  1053.     if (*t==-1) return; 
  1054. }    
  1055.  
  1056. int _getth(bt,ot)
  1057. int bt,ot;
  1058. {
  1059.     char buf[7];
  1060.     int n;
  1061.     
  1062.     g_gets(buf,7,"=CM<,");
  1063.     if (ESC) return(bt);
  1064.     switch(tpr(buf[0])){
  1065.         case '=': return(ot);
  1066.         case 'C': return(-1);
  1067.         case 'M': return(maxit);
  1068.         case '<': 
  1069.         case ',': return(maxit-1);
  1070.         case 0  : return(bt);
  1071.     }
  1072.     n=atoi(buf);
  1073.     if ((n<=0)||(n>maxit)) { ESC=1; return(bt); }
  1074.     return(n);
  1075. }
  1076. int auto_levels(b,t)
  1077. int *b,*t;
  1078. {
  1079.     int first,last,start,size,gap,stopval,tt;
  1080.     int i,val;
  1081.     char s[50];
  1082.     
  1083.     g_write("\rAuto-draw. First cluster number? ");
  1084.     g_gets(s,10,"");
  1085.     if (ESC) return(0);
  1086.     if (s[0]==0) { first=0; g_putc('0'); }
  1087.     else first=atoi(s);
  1088.     g_write(" Last cluster number? ");
  1089.     g_gets(s,10,"");
  1090.     if (ESC) return(0);
  1091.     if (s[0]==0) last=NUMLEVELS-1;
  1092.     else last=atoi(s);
  1093.             
  1094.     sprintf(s,"\rcluster %d-%d ",first,last);
  1095.     g_write(s);
  1096.     tt=g_th;
  1097.     g_write("Lowest pixel value? ");
  1098.     
  1099.     g_gets(s,10,"");
  1100.     if (ESC) return(0);
  1101.     if (tpr(s[0])=='C') {
  1102.         for (i=first;i<=last;i++) t[i]=(-1);
  1103.         return 1;
  1104.     }
  1105.     g_th=tt;
  1106.     g_write("v=");
  1107.     g_write(s);
  1108.     if (s[0]==0) { g_putc('1'); start=1; }
  1109.     else if ((start=atoi(s))<0) return(0);
  1110.     tt=g_th+1;
  1111.     g_write(" Cluster size? ");
  1112.     g_gets(s,10,"");
  1113.     if (ESC) return(0);
  1114.     g_th=tt;
  1115.     g_write("s=");
  1116.     g_write(s);
  1117.     if (s[0]==0) { size=1; g_putc('1'); }
  1118.     else if ((size=atoi(s))<=0) return(0);
  1119.     tt=g_th+1;
  1120.     g_write(" Cluster gap? ");
  1121.     g_gets(s,10,"");
  1122.     if (ESC) return(0);
  1123.     g_th=tt;
  1124.     g_write("g=");
  1125.     g_write(s);
  1126.     if (s[0]==0) { gap=1; g_putc('1'); }
  1127.     else if ((gap=atoi(s))<=0) return(0);
  1128.     g_write(" Largest pixel value? ");
  1129.     g_gets(s,10,"");
  1130.     if (ESC) return(0);
  1131.     stopval=atoi(s);
  1132.     if (stopval<=0) stopval=maxit-1;
  1133.     
  1134.     eratline();
  1135.     if ((first<0)||(last>=NUMLEVELS)||(first>=last)||(start>=maxit)) {
  1136.         g_write("Invalid parameter(s). Press any key. ");
  1137.         blink_getc(340,g_th,screen0);
  1138.         return(0);
  1139.     }
  1140.     for (i=first,val=start;i<=last;i++){
  1141.         b[i]=val;
  1142.         val+=(size-1);
  1143.         t[i]=val;
  1144.         if (t[i]>stopval){
  1145.             t[i]=(-1);
  1146.             break;
  1147.         }
  1148.         val+=(gap+1);
  1149.     }
  1150.     while (i<=last){
  1151.         t[i]=(-1);
  1152.         i++;
  1153.     }
  1154.     return(1);
  1155. }
  1156. void redraw(top,bottom,i,interrupt)
  1157. int *top,*bottom,i,interrupt;
  1158. {
  1159.     register unsigned char dat;
  1160.     int numl,h,v,level;
  1161.     unsigned char table[1024];
  1162.     
  1163. #ifdef FREEBLOCKS
  1164.     char trashh, trash;
  1165.     stackcount=stackp-&trash;
  1166. #endif
  1167.     g_write("\rPlease wait. ");
  1168.     if (!interrupt) {
  1169.         numl=1;
  1170.         top[0]=bottom[0]=maxit;
  1171.     }
  1172.     else {
  1173.         numl=NUMLEVELS;
  1174.         while (top[numl-1]==(-1)) {
  1175.             numl--;
  1176.             if (numl==0) {
  1177.                 clearscreen(0);
  1178.                 return;
  1179.             }
  1180.         }
  1181.     }
  1182.     if (maxit>255) for (v=0;v<1024;v++){
  1183.         for(level=0;level<numl;level++)
  1184.             if ((v>=bottom[level])&&(v<=top[level])){
  1185.                 table[v]=1;
  1186.                 break;
  1187.             }
  1188.         if (level==numl) table[v]=0;
  1189.         if (!(v&127)) g_putc('.');
  1190.     }
  1191.     else for (v=0;v<256;v++){
  1192.         for(level=0;level<numl;level++)
  1193.             if ((v>=bottom[level])&&(v<=top[level])){
  1194.                 table[v]=1;
  1195.                 break;
  1196.             }
  1197.         if (level==numl) table[v]=0;
  1198.     }
  1199.     if (interrupt) g_write("\rPress <BS> to interrupt... ");
  1200.     for (v=0,numl=height;v<height;v++,numl--){
  1201.         if ((interrupt)&&(inkey()==8)) break;
  1202.         revdot(v,719);
  1203.         if (maxit>255){
  1204.             for (h=0;h<i;h+=8){
  1205.                 level=dat=0;
  1206.                 for (;level<8;level++)
  1207.                     dat |= (table[getdata(v,h+level)])<<(7-level);
  1208.                 writebyte(dat,v,h>>3);
  1209.             }
  1210.         }
  1211.         else {
  1212.             for (h=0;h<i;h+=8){
  1213.                 level=dat=0;
  1214.                 for (;level<8;level++)
  1215.                     dat |= (table[pdata[h+level][v]])<<(7-level);
  1216.                 writebyte(dat,v,h>>3);
  1217.             }
  1218.         }
  1219.         revdot(v,719);
  1220.         if (!(numl%20)) g_putc(numl/20+64);
  1221.     }
  1222. }    
  1223. void writepict()
  1224. {
  1225.     char fn[NAMELEN],s[200];
  1226.     int f,sd,i;
  1227.     
  1228.     mypctname(fn);
  1229.     if (PIC_SIZE > diskfree()){
  1230.         g_write("\rInsufficient disk space. Press any key... ");
  1231.         blink_getc(340,g_th,screen0);
  1232.         return;
  1233.     } 
  1234.     if ((f=open(fn,O_WRONLY|O_TRUNC))==-1){
  1235.         g_write("\rCannot open file: ");
  1236.         g_write(fn);
  1237.         blink_getc(340,g_th,screen0);
  1238.         return;
  1239.     }
  1240.     sd=15;
  1241.     do {
  1242. #ifdef JULIA
  1243.         sprintf(s,"KITTENSOFT \001 Lr=%.*g%c Ti=%.*g%c Bi=%.*g%c rj=%.*g%c ij=%.*g%c",sd,rcorner,STRIPZ_C,sd,icorner,STRIPZ_C,sd,bottom,STRIPZ_C,sd,rjulia,STRIPZ_C,sd,ijulia,STRIPZ_C);
  1244. #else
  1245.         sprintf(s,"KITTENSOFT \001 Lr=%.*g%c Ti=%.*g%c Bi=%.*g%c mag=%.3g",sd,rcorner,STRIPZ_C,sd,icorner,STRIPZ_C,sd,bottom,STRIPZ_C,3.0/(icorner-bottom));
  1246. #endif
  1247.         sd--;
  1248.         stripz(s);
  1249.     } while (strlen(s)>P_DATA_NUM/8);
  1250.     
  1251.     eratline();
  1252.     for (i= (84-strlen(s))>>1; i; i--) g_putc(' ');
  1253.     g_write(s);
  1254.     sd=15;
  1255.     do {
  1256. #ifdef JULIA
  1257.         sprintf(s,"ejulia %.*g%c %.*g%c %.*g%c %.*g%c %.*g%c /m%d /s%.3g%c /a%.3g%c /n%s\n%c",sd,rcorner,STRIPZ_C,sd,icorner,STRIPZ_C,sd,bottom,STRIPZ_C,sd,rjulia,STRIPZ_C,sd,ijulia,STRIPZ_C,maxit,wsize,STRIPZ_C,aspect,STRIPZ_C,filename,26);
  1258. #else
  1259.         sprintf(s,"emandel %.*g%c %.*g%c %.*g%c /m%d /s%.3g%c /a%.3g%c /n%s\n%c",sd,rcorner,STRIPZ_C,sd,icorner,STRIPZ_C,sd,bottom,STRIPZ_C,maxit,wsize,STRIPZ_C,aspect,STRIPZ_C,filename,26);
  1260. #endif
  1261.         sd--;
  1262.         stripz(s);
  1263.     } while (strlen(s) > BATCH_LENGTH);
  1264.     while(strlen(s)<160) strcat(s,"\032");
  1265.     write(f,s,strlen(s));
  1266.     write(f,(char *)&height,2);
  1267.     write(f,(char *)&xwidth,2);
  1268.     write(f,virtscreen,virt_size);
  1269.     for (i=340;i<348;i++)
  1270.         write(f,screen0+ 0x2000 * (i&3) + 90*(i>>2),P_DATA_NUM/8);
  1271.     close(f);
  1272.     
  1273.     sprintf(s,"\rDone. fn=%s Press any key... ",fn);
  1274.     g_write(s);
  1275.     blink_getc(340,g_th,screen0);
  1276. }
  1277. void showlevels(b,t)
  1278. int *b,*t;
  1279. {
  1280.     int i,numl=NUMLEVELS;
  1281.     char gbuf[100];
  1282.     
  1283.     while (t[numl-1]==(-1)){
  1284.         numl--;
  1285.         if (!numl) break;
  1286.     }
  1287.     g_th=0;
  1288.     if (!numl) sprintf(gbuf,"All levels clear. ");
  1289.     else for (i=0,gbuf[0]=0;i<numl;i++){
  1290.         if (t[i]==(-1)) sprintf(gbuf+strlen(gbuf),"<%d>=cl ",i);
  1291.         else sprintf(gbuf+strlen(gbuf),"<%d>=%d-%d ",i,b[i],t[i]);
  1292.         if (strlen(gbuf)>75){
  1293.             if (i==numl-1) break;
  1294.             g_write(gbuf);
  1295.             if (blink_getc(340,g_th,screen0)==27) return;
  1296.             gbuf[0]=0;
  1297.         }
  1298.     }
  1299.     g_write(gbuf);
  1300.     g_th--;
  1301.     g_write(". ");
  1302.     blink_getc(340,g_th,screen0);
  1303. }
  1304. void mybatname(fn,prg)
  1305. char *fn,*prg;
  1306. {
  1307.     int fnum;
  1308.  
  1309.     for (fnum=0;fnum<=99;fnum++){
  1310.         sprintf(fn,"%s%d.bat",prg,fnum);
  1311.         if (access(fn,0)) break;
  1312.     }
  1313. }
  1314. void mypctname(fn)
  1315. char *fn;
  1316. {
  1317.     int fnum;
  1318.     char *wp,s[NAMELEN];
  1319.     
  1320.     strcpy(s,filename);
  1321.     if (wp=index(s,'.')) *wp=0;
  1322.     wp=rindex(s,'\\');
  1323.     if (wp==0) wp=s;
  1324.     *(wp+6)=0;
  1325.     for (fnum=0;fnum<=99;fnum++){
  1326.         sprintf(fn,"%s%d.PIC",s,fnum);
  1327.         if (access(fn,0)) break;
  1328.     }
  1329. }
  1330. void makebat(rleft,itop,bottom,asp,name,j)
  1331. double rleft,itop,bottom,asp;
  1332. char *name;
  1333. int j;
  1334. {
  1335.     char fn[50],pfn[50],s[15],batch[200],ms[12],ss[50],as[50];
  1336.     int newmax,dl,fd;
  1337.     double newsize;
  1338.  
  1339. #ifdef JULIA
  1340.     mybatname(fn,"ejulia");
  1341. #else
  1342.     if (j=='j') mybatname(fn,"ejulia");
  1343.     else mybatname(fn,"emand");
  1344. #endif
  1345.  
  1346.     strcpy(pfn,"/n");  
  1347.     if (name) {
  1348.         strcat(pfn,name);
  1349.         newmax=maxit;
  1350.         newsize=wsize; 
  1351.     }
  1352.     else {
  1353.         g_write("\rEnter .PIK file name or <CR> ");
  1354.         g_gets(pfn+2,40,"");
  1355.         if (ESC) { g_write("\rAborted. "); return; }
  1356.         if (pfn[2]==0) pfn[0]=0;
  1357.         if (j=='j'){
  1358.             newmax=255; 
  1359.         }
  1360.         else {
  1361.             g_write("  maxit? ");
  1362.             newmax=atoi(g_gets(s,10,""));
  1363.             if (ESC) { g_write("\rAborted. "); return; }
  1364.             if (newmax<=0) newmax=maxit;
  1365.         }
  1366.         g_write("  Size? (.05 to 1) ");
  1367.         g_gets(s,10,"");
  1368.         if (ESC) { g_write("\rAborted. "); return; }
  1369.         if (!s[0]) newsize=1.0;
  1370.         else newsize=atof(s); 
  1371.             
  1372.     }
  1373.     if (newmax==255) ms[0]=0;
  1374.     else sprintf(ms,"/m%d ",newmax);
  1375.     if (newsize==1.0) ss[0]=0;
  1376.     else sprintf(ss,"/s%g%c ",newsize,STRIPZ_C);
  1377.     if (asp==0.75) as[0]=0;
  1378.     else sprintf(as,"/a%g%c ",asp,STRIPZ_C);
  1379.  
  1380.     if ((fd=open(fn,O_WRONLY|O_TRUNC))==-1) {
  1381.         g_write("\rCan't make batch file. ");
  1382.         return;
  1383.     }
  1384.     dl=15;
  1385.     do {
  1386. #ifdef JULIA
  1387.     sprintf(batch,"ejulia %.*g%c %.*g%c %.*g%c %.*g%c %.*g%c %s%s%s%s",dl,rleft,STRIPZ_C,dl,itop,STRIPZ_C,dl,bottom,STRIPZ_C,dl,rjulia,STRIPZ_C,dl,ijulia,STRIPZ_C,ms,ss,as,pfn);
  1388. #else
  1389.     if (j=='j') sprintf(batch,"ejulia %.*g%c %.*g%c %.*g%c %.*g%c %.*g%c %s%s%s%s",dl,rleft,STRIPZ_C,dl,itop,STRIPZ_C,dl,bottom,STRIPZ_C,dl,rjulia,STRIPZ_C,dl,ijulia,STRIPZ_C,ms,ss,as,pfn);
  1390.     else sprintf(batch,"emandel %.*g%c %.*g%c %.*g%c %s%s%s%s",dl,rleft,STRIPZ_C,dl,itop,STRIPZ_C,dl,bottom,STRIPZ_C,ms,ss,as,pfn);
  1391. #endif
  1392.     stripz(batch);
  1393.     dl--;
  1394.        } while (strlen(batch) > BATCH_LENGTH);
  1395.  
  1396.     sprintf(batch+strlen(batch),"\r\nIF NOT ERRORLEVEL 1 DEL %s\r\n",fn);
  1397.     write (fd,batch,strlen(batch));
  1398.     close(fd);
  1399.     
  1400.     g_write("\rBatch file name: ");
  1401.     g_write(fn);
  1402.     g_putc(' ');
  1403. }
  1404. void mynewname()
  1405. {
  1406.     int fnum;
  1407.  
  1408.     for (fnum=0;fnum<=999;fnum++){
  1409. #ifdef JULIA
  1410.         sprintf(filename,"EJ%d.PIK",fnum);
  1411. #else 
  1412.         sprintf(filename,"EM%d.PIK",fnum);
  1413. #endif
  1414.         if (access(filename,0)) break;
  1415.     }
  1416. }
  1417. /* v and h are pixel addresses, not col, line */
  1418. void g_write(s)
  1419. char *s;
  1420. {
  1421.     int temp;
  1422.     
  1423.     _s_p_l( strlen(s) + g_th - 89 );
  1424.     while (*s) {
  1425.         if (*s=='\r'){
  1426.             s++;
  1427.             g_th=0;
  1428.             continue;
  1429.         }
  1430.         g_putch(*s++,340,g_th++,screen0);
  1431.     }
  1432.     
  1433.     for ( temp=g_th ; temp<90 ; temp++ )
  1434.         g_putch(' ',340,temp,screen0);
  1435.     
  1436. }
  1437. void g_putch(c,y,x,scr)
  1438. int c,y,x;
  1439. unsigned char *scr;
  1440. {
  1441.     int i;
  1442.     
  1443.     for (i=0;i<8;i++,y++)
  1444.         scr[( 0x2000 * (y&3) + 90*(y>>2) + x)] = font[c*8+i];
  1445.     
  1446. }
  1447. void g_putc(c)
  1448. int c;
  1449. {
  1450.     char s[2];
  1451.     
  1452.     if (c=='\b'){
  1453.         g_th--;
  1454.         g_putch(' ',340,g_th,screen0);
  1455.         return;
  1456.     }
  1457.     s[0]=c;
  1458.     s[1]=0;
  1459.     g_write(s); 
  1460. }
  1461. void _s_p_l(n)
  1462. int n;
  1463. {
  1464.     int i;
  1465.     static int off[8] = {
  1466.         0x1de2,0x3de2,0x5de2,0x7de2,0x1e3c,0x3e3c,0x5e3c,0x7e3c };
  1467.     
  1468.     if (n<=0) return;
  1469.     for(i=0;i<8;i++) memcpy(screen0+off[i],screen0+off[i]+n,90-n);
  1470.     g_th -= n;
  1471. }
  1472. int tpr(c)
  1473. int c;
  1474. {
  1475.     if ((c>='a')&&(c<='z')) c ^= 32;
  1476.     return(c);
  1477. }
  1478. void uppername(s)
  1479. char *s;
  1480. {
  1481.     
  1482.     while (*s) (*s++)=tpr(*s);
  1483. }
  1484. void flash()
  1485. {
  1486.     g1_tv=100;
  1487.     g1_th=30;
  1488.     g1_write("Use ^S to restore screen.");
  1489.     sleep(FLASH_DELAY);
  1490.     g1_th=30;
  1491.     g1_write("                         ");
  1492. }
  1493. int options(r)
  1494. int r;
  1495. {
  1496.     char s[40];
  1497.     double t,f;
  1498.     int be;
  1499.     
  1500.     if (r==19) { sw_scr(); return(0); }
  1501.     if (scr_num) {
  1502.         if ((r==3)||(r=='?')) flash();
  1503.         return(0);        /* Ignore inputs on screen1. */
  1504.     }
  1505.     if (nz_ex) {
  1506.         nz_ex=0;
  1507.         g_write("nZ off. ");
  1508.     }
  1509.     switch(r){
  1510.         case 17: return(17); break;
  1511.         case 3:  g_write("(^Q)uit calculation before exit. "); break;
  1512.         case 12: lognew(1); break;
  1513.         case 23: return(save()); 
  1514.         case ' ': eratline(); break;
  1515.         case 7:  grid(); return('w');
  1516.         case 20: thresh_view(); return('w');
  1517.         case '?': soundoff(0); break;
  1518.         case 5:  
  1519.             nz_ex=1; 
  1520.             g_write("nZ on. ");
  1521.             break;
  1522.         case 2:
  1523.             sprintf(s,"Beep alarm: %d New value? ",beep);
  1524.             g_write(s);
  1525.             be=g_getreply("0123456789\r");
  1526.             if (be != '\r') beep=be-48;
  1527.             sprintf(s,"Beep alarm=%d ",beep);
  1528.             g_write(s);
  1529.             break;
  1530.         case 24:
  1531.             autoexit ^= 1;
  1532.             if (autoexit) g_write("autoeXit on. ");
  1533.             else g_write("autoeXit off. ");
  1534.             break;
  1535.         case 18:
  1536.             makebat(rcorner,icorner,bottom,aspect,filename,0);
  1537.             break;
  1538.         case 15:
  1539.             g_write("\rExpansion factor? (integer >= 1) ");
  1540.             f= ( atoi( g_gets(s,10,"") )  -1.0) /2.0;
  1541.             if (f < 0.0) {
  1542.                 g_write(" Aborted. ");
  1543.                 break;
  1544.             }
  1545.             t=((icorner-bottom)*f);
  1546.             makebat(rcorner-((((height<<2)/3)*increment)*f), icorner+t, bottom-t, ASPECT, (char *)0, 0 );
  1547.             break;
  1548.     }
  1549.     return(0);
  1550. }
  1551. int calculate()
  1552. {
  1553.     register double real,imag,a,b,a2,b2,t;
  1554.     register int count;
  1555.     int r,j;
  1556.     
  1557.     g_write(working);
  1558.     for(;ii<xlimit;ii++){
  1559.         real=rcorner+(ii*increment);
  1560.         for (j=0;j<ylimit;j++){
  1561.             if (r=inkey()){
  1562.                 k_timer(0);
  1563.                 r=options(r);
  1564.                 k_timer(1);
  1565.                 switch (r) {
  1566.                     case 17: return(1);
  1567.                     case 'w': g_write(working);
  1568.                 }
  1569.             }
  1570.             writedot(j,ii);
  1571.             imag=icorner-(j*increment);
  1572.             a=real;
  1573.             b=imag;
  1574.             a2=a*a;
  1575.             b2=b*b;
  1576.             for (count=1;count<maxit;count++){
  1577.                 t=a;
  1578. #ifdef JULIA
  1579.                 a= a2 - b2 + rjulia ;
  1580.                 b= 2*t*b + ijulia ;
  1581. #else
  1582.                 a= a2 - b2 + real ;  
  1583.                 b= 2*t*b + imag ;
  1584. #endif
  1585.                 a2=a*a;
  1586.                 b2=b*b;
  1587.                 if ((a2+b2) > 4.0) break;    
  1588.             }
  1589.             cleardot(screen1,j,ii);
  1590.             if (count < maxit) cleardot(screen0,j,ii);
  1591.             pdata[ii][j]=count;
  1592.         }
  1593.     }
  1594.     return(0);
  1595. }
  1596. int hc_calculate()
  1597. {
  1598.     register double real,imag,a,b,a2,b2,t;
  1599.     register int count;
  1600.     int r,j,off;
  1601.     
  1602.     g_write(working);
  1603.     for(;ii<xlimit;ii++){
  1604.         real=rcorner+(ii*increment);
  1605.         for (j=0,off=(-1);j<ylimit;j++){
  1606.             if ((j&3)==0) off++;
  1607.             if (r=inkey()){
  1608.                 k_timer(0);
  1609.                 r=options(r);
  1610.                 k_timer(1);
  1611.                 switch (r) {
  1612.                     case 17: return(1);
  1613.                     case 'w': g_write(working);
  1614.                 }
  1615.             }
  1616.             writedot(j,ii);
  1617.             imag=icorner-(j*increment);
  1618.             a=real;
  1619.             b=imag;
  1620.             a2=a*a;
  1621.             b2=b*b;
  1622.             for (count=1;count<maxit;count++){
  1623.                 t=a;
  1624. #ifdef JULIA
  1625.                 a= a2 - b2 + rjulia ;
  1626.                 b= 2*t*b + ijulia ;
  1627. #else
  1628.                 a= a2 - b2 + real ;  
  1629.                 b= 2*t*b + imag ;
  1630. #endif
  1631.                 a2=a*a;
  1632.                 b2=b*b;
  1633.                 if ((a2+b2) > 4.0) break;    
  1634.             }
  1635.             cleardot(screen1,j,ii);
  1636.             if (count < maxit) cleardot(screen0,j,ii);
  1637.  
  1638.             count <<= (6 - (j&3)*2 );
  1639.             pdata[ii][off++] |= count>>8;
  1640.             pdata[ii][off] = count & 0xff ;
  1641.  
  1642.         }
  1643.     }
  1644.     return(0);
  1645. }
  1646. int getdata(v,h)
  1647. int v,h;
  1648. {
  1649.     int off,val;
  1650.     
  1651.     off= v+(v>>2);
  1652.     
  1653.     val= pdata[h][off++]<<8;
  1654.     val |= pdata[h][off];
  1655.     
  1656.     val>>= ( 6 - ((v&3)<<1) );
  1657.     return(val & 1023);    
  1658. }
  1659. int blink_getc(v,h,scr)
  1660. int h,v;
  1661. unsigned char *scr;
  1662. {
  1663.     int i,c;
  1664.     
  1665.     if (h>=90) h=89;
  1666.     for(c=0;;){
  1667.         for(i=5;i;i--){
  1668.             if (c=inkey()) break; 
  1669.             sleep(B_DELAY);
  1670.         }
  1671.         blink(h,v,scr);
  1672.         if (c==0) for(i=5;i;i--){
  1673.             if (c=inkey()) break; 
  1674.             sleep(B_DELAY);
  1675.         }
  1676.         blink(h,v,scr);
  1677.         if (c) return(c);
  1678.     }
  1679. }
  1680. void sleep(t)
  1681. int t;
  1682. {
  1683.     long a;
  1684.     
  1685.     a=clock();
  1686.     while(clock()-a<t)
  1687.         ;
  1688. }
  1689.  
  1690. void blink(h,v,scr)
  1691. int h,v;
  1692. unsigned char *scr;
  1693. {
  1694.     int i;
  1695.     
  1696.     for (i=0;i<8;i++,v++)
  1697.         scr[0x2000 * (v&3) + 90*(v>>2) + h] ^= 0xff;
  1698. }
  1699. char *g_gets(s,max,qr)
  1700. char *s,*qr;
  1701. int max;
  1702. {
  1703.     int i,j,c;
  1704.     
  1705.     ESC=0;
  1706.     max--;
  1707.     for (i=0;i<max;){
  1708.         c=blink_getc(340,g_th,screen0) ;
  1709.         if (c==13) break;
  1710.         if (c==27) { s[0]=0; ESC=1; return(s); }
  1711.         if (c==8) {
  1712.             if (!i) continue;
  1713.             g_putc(8);
  1714.             i--;
  1715.             continue;
  1716.         }
  1717.         if ((c<=32)||(c>126)) continue;
  1718.         s[i++]=c;
  1719.         g_putc(c);
  1720.         if (i==1)
  1721.             for (j=0;qr[j];j++) if (tpr(c)==qr[j]) {
  1722.                 s[1]=0;
  1723.                 return s;
  1724.             }
  1725.     }
  1726.     s[i]=0;
  1727.     return(s);
  1728. }
  1729.  
  1730. char *helptext[4] = { 
  1731. "\
  1732. MAIN COMMANDS:\n\
  1733. \n\
  1734. ^B  Set/change beeper-alarm.\n\
  1735. ^C  Exit from program.\n\
  1736. ^E  nZ.\n\
  1737. ^G  Enter Grid mode.\n\
  1738. ^L  Log new drive:directory.\n\
  1739. ^O  Oversized surrounding frame.\n\
  1740. ^Q  Quit calculation mode.\n\
  1741. ^R  Repeat current frame.\n\
  1742. ^S  Blank/restore screen.\n\
  1743. ^T  Thresh-view mode.\n\
  1744. ^U  Resume calculation after ^Q.\n\
  1745. ^W  Save data file.\n\
  1746. ^X  Toggle auto-exit.\n\
  1747. <space bar> Erase prompt line.\n\n\n",
  1748.  
  1749. "\
  1750. GRID COMMANDS:\n\
  1751. \n\
  1752. Number pad keys move crosshairs.\n\
  1753. (Number pad 5 is stop.)\n\
  1754. \n\
  1755. +  Increase speed.\n\
  1756. *  Increase speed faster.\n\
  1757. -  Reduce speed.\n\
  1758. BS (Backspace) Set speed to 1.\n\
  1759. .  (Del) Toggle glide.\n\
  1760. \n\
  1761. ^B  Open or enlarge grid window.\n\
  1762. ^S  Shrink grid window.\n\
  1763. ^U  Window bottom Up.\n\
  1764. ^D  Window bottom Down.\n\
  1765. ^L  Window right-edge Left.\n\
  1766. ^R  Window right-edge Right.\n\
  1767. 0   Close grid window.\n\
  1768. #   (Crosshatch) Write batch file for present grid window.\n\
  1769. ^J  Write Julia batch file from Mandelbrot.\n\
  1770. \n\
  1771. <space bar> Erase prompt line.\n\
  1772. ESC  Exit Grid mode.\n\n",
  1773.  
  1774. "\
  1775. THRESH-VIEW COMMANDS:\n\
  1776. A  Auto-draw.\n\
  1777. G  Grid.\n\
  1778. R  Re-draw screen.\n\
  1779. M  Mask shift.\n\
  1780. V  View cluster values.\n\
  1781. L  Log new drive:directory.\n\
  1782. W  Write picture file of present display.\n\
  1783. ?  Display this screen.\n\
  1784. ESC Exit Thresh-view mode.\n\
  1785. Cluster may be any number from 0 to $      \n\
  1786. =  Equalize top/bottom.\n\
  1787. C  Clear present cluster.\n\
  1788. M  maxit.\n\
  1789. <  maxit less 1.\n\
  1790. <backspace> Interrupt screen re-draw.\n\
  1791. \nAUTO-DRAW:\n\
  1792. To abort: Press Esc at any prompt.\n\
  1793. To clear: Enter C at START prompt.\n\
  1794. <CR> at FIRST prompt = 0\n\
  1795. <CR> at LAST prompt = $        \n\
  1796. <CR> at STOP prompt disables stop.\n\
  1797. <CR> at START, SIZE or GAP prompt = 1\n",
  1798.  
  1799. "\
  1800. \tDISPLAY COMMANDS:\n\
  1801. \t\n\
  1802. \t?B  Beep alarm.\n\
  1803. \t?C  Coordinates.\n\
  1804. \t?G  Magnification.\n\
  1805. \t?H  Horizontal position.\n\
  1806. \t?J  Julia point.\n\
  1807. \t?M  Maxit.\n\
  1808. \t?N  File name.\n\
  1809. \t?P  Path.\n\
  1810. \t?S  Frame size.\n\
  1811. \t?T  Time totals.\n\
  1812. \t?X  Autoexit status.\n\
  1813. \t?%  Percent completed.\n\
  1814. \t?I  Increment.\n\
  1815. \t??  Display this screen.",
  1816. };
  1817.  
  1818. void help(q)
  1819. int q;
  1820. {
  1821.     int i,j;
  1822.     char *wp1,*wp2,num[10],s[100];
  1823.     
  1824.     sprintf(num,"%d",NUMLEVELS-1);
  1825.     wp1=strchr(helptext[2],'$');
  1826.     wp2=strchr(wp1+1,'$');
  1827.     if (wp1 && wp2) for(i=0;num[i];i++,wp1++,wp2++) *wp1=*wp2=num[i];
  1828.  
  1829.     sw_scr();
  1830. #ifdef JULIA
  1831.     sprintf(s,"\014Ejulia from KITTENSOFT. %s.\n\n",version);
  1832. #else
  1833.     sprintf(s,"\014Emandel from KITTENSOFT. %s.\n\n",version);
  1834. #endif
  1835.     g1_write(s);
  1836.     g1_write(helptext[q]);
  1837.     g1_write("\nSEE MANDEL.DOC FOR DETAILED INSTRUCTIONS  \002  PRESS ANY KEY TO RETURN TO ");
  1838.     
  1839.     switch(q){
  1840.         case 0: g1_write("THE PROGRAM. "); 
  1841.             i=g1_th;
  1842.             j=g1_tv;
  1843.             g1_tv=24;
  1844.             vline(24,215,36); 
  1845.             g1_write(helptext[3]);
  1846.             break;
  1847.         case 1: g1_write("GRID. "); 
  1848.             i=g1_th;
  1849.             j=g1_tv;
  1850.             g1_tv=24;
  1851.             vline(24,215,37); 
  1852.             g1_write(helptext[3]);
  1853.             break;
  1854.         case 2: g1_write("THRESHVIEW. ");
  1855.             i=g1_th;
  1856.             j=g1_tv;
  1857.             hline(8912,0,20);
  1858.             hline(11342,0,39);
  1859.             hline(21154,0,39);
  1860.             hline(29346,0,39);
  1861.             hline(13502,0,9);
  1862.             break;
  1863.     }
  1864.     blink_getc(j,i,screen1);
  1865.     sw_scr();
  1866.     clearscreen(1);
  1867. }
  1868. void g1_write(s)
  1869. char *s;
  1870. {
  1871.     
  1872.     while (*s) {
  1873.         if (*s=='\014'){
  1874.             clearscreen(1);
  1875.             g1_th=g1_tv=0;
  1876.             s++;
  1877.             continue;
  1878.         }
  1879.         if (*s=='\n'){
  1880.             g1_th=0;
  1881.             g1_tv+=12;
  1882.             s++;
  1883.             continue;
  1884.         }
  1885.         if (*s=='\t'){
  1886.             g1_th=40;
  1887.             s++;
  1888.             continue;
  1889.         }
  1890.         g_putch(*s++,g1_tv,g1_th++,screen1);
  1891.     }
  1892. }
  1893.  
  1894. void g1_putchar(c)
  1895. int c;
  1896. {
  1897.     char s[2];
  1898.     
  1899.     s[0]=c;
  1900.     s[1]=0;
  1901.     g1_write(s); 
  1902. }
  1903. int g_getreply(s)
  1904. char *s;
  1905. {
  1906.     char *wp;
  1907.     int c;
  1908.     
  1909.     for(;;){
  1910.         g_putc(c=blink_getc(340,g_th,screen0)) ;
  1911.         c=tpr(c);
  1912.         for(wp=s;*wp;wp++) if (*wp==c) return(c);
  1913.     }
  1914. }
  1915. void writebyte(dat,y,x)   
  1916. int x,y,dat;
  1917. {
  1918.     
  1919.     virtscreen[xwidth8*y + x]=dat;
  1920.     
  1921.     if (y%3==0) return;
  1922.     y-=((y/3)+1);
  1923.  
  1924.     screen0[0x2000 * (y&3) + 90*(y>>2) + x]=dat;
  1925.     
  1926. }
  1927. #ifdef FREEBLOCKS
  1928. void countfree()
  1929. {
  1930.     int i;
  1931.     
  1932.     for (i=0;i<512;i++)
  1933.         if ((freep[i]=malloc(1024))==0) break;
  1934.         
  1935.     numfree=i;    
  1936.     while (i--) free(freep[i]);
  1937. }
  1938. #endif
  1939.  
  1940. long diskfree()
  1941. {
  1942.     struct {
  1943.         int ax,bx,cx,dx,si,di,ds,es;
  1944.     } reg_s;
  1945.     
  1946.     reg_s.ax = 0x36 << 8;
  1947.     reg_s.bx = reg_s.cx = reg_s.dx = reg_s.si = reg_s.di = reg_s.es = reg_s.ds = 0;
  1948.     sysint(0x21,®_s,®_s);
  1949.     groupsize = reg_s.ax * reg_s.cx;
  1950.  
  1951.     return ((long)reg_s.bx * (long)groupsize);
  1952. void lognew(q)
  1953. int q;
  1954. {
  1955.     char s[200],*wp;
  1956.     
  1957.     if (q==1){
  1958.         sprintf(s,"Current path is %c:\\%s  Enter new path: ",drivenum+65,pathname);
  1959.         g_write(s);
  1960.         g_gets(s,25,"");
  1961.         parsepath(s);
  1962.     }
  1963.     sprintf(s," Path> %c:\\%s ",drivenum+65,pathname);
  1964.     g_write(s);
  1965. }    
  1966. int newpath(s)
  1967. char *s;
  1968. {
  1969.     int q;
  1970.     
  1971.     if (s) if (chdir(s)==(-1)) return(-1);
  1972.     
  1973.     if (!getcwd(pathname,PATHLEN-1)) return(-1);
  1974.     else return(0);
  1975.     
  1976. }
  1977.  
  1978. void newdrive(d)
  1979. int d;
  1980. {
  1981.  
  1982.     if (d==(-1)){
  1983.         drivenum=bdos(0x19,0,0);
  1984.         newpath((char *)0);
  1985.         return;
  1986.     }
  1987.     bdos(0xe,d,d);
  1988.     newdrive(-1);
  1989. }
  1990. void parsename(s)
  1991. char *s;
  1992. {
  1993.     char *wp;
  1994.     int fd;
  1995.     
  1996.     uppername(s);
  1997.  
  1998.     if (wp=strrchr(s,'\\')) wp++;
  1999.     else {
  2000.         if (wp=strchr(s,':')) wp++;
  2001.         else wp=s;
  2002.     }
  2003.     strcpy (filename,wp);
  2004.  
  2005.     if (wp=index(filename,'.')) *wp=0;
  2006.     strcat(filename,".PIK"); 
  2007.     if ((strlen(filename)>=NAMELEN)||( ((fd=open(filename,O_WRONLY|O_CREAT))==-1) )){
  2008.         printf("\n*** %s not a valid file name.\n",filename);
  2009.         ng_help(0);
  2010.         exitt(10);
  2011.     }
  2012.     close(fd);
  2013.     if ( filesize(filename)==0L ) unlink(filename);
  2014. }
  2015. void parsepath(s)
  2016. char *s;
  2017. {
  2018.     char *wp;
  2019.     
  2020.     uppername(s);
  2021.     wp=strrchr(s,':');
  2022.     if (wp) {
  2023.         if (wp-1 != s) return;
  2024.         newdrive(s[0]-65);
  2025.         wp++;
  2026.     }
  2027.     else (wp=s);
  2028.     if (*wp) newpath(wp);
  2029. }
  2030. long filesize(n)
  2031. char *n;
  2032. {
  2033.     long size;
  2034.     int fd;
  2035.     
  2036.     if ((fd=open(n,O_RDONLY))==-1) return(0L);
  2037.  
  2038.     size=lseek(fd,0L,2);
  2039.     close(fd);
  2040.     
  2041.     return(size);
  2042. }
  2043.  
  2044. void exitt(q)
  2045. {
  2046.  
  2047. #ifdef HOGMEM
  2048.     for (;hogmem;hogmem--) free(hog[hogmem-1]);
  2049. #endif
  2050.     exit(q);
  2051. }
  2052. /* Aztec C-86 version 4.10b dated 11-12-87 has a bad bug in atof().
  2053. The following is my workaround. It is probably inefficient but seems
  2054. to be accurate enough for the purposes of this program. */
  2055. double atof(s)
  2056. char *s;
  2057. {
  2058.     char     is[_STRTODLEN_], /* string to hold the integer portion */
  2059.         fs[_STRTODLEN_], /* string to hold the fractional portion */
  2060.         es[_STRTODLEN_]; /* string to hold the exponent portion */
  2061.     double     ii,        /* the integer part as a double */
  2062.         fi,        /* the fractional part as a double */
  2063.         efac;        /* a factor, such that e3 becomes efac=1000, e45 becomes ecac=10^45, e-17 becomes efac=10^(-17), etc. */
  2064.     int     ei,        /* the power of 10 */
  2065.         flen,        /* the length of the string representing the fractional part */
  2066.         sign=1,        /* sign=0 if the number is < 0. */
  2067.         esign=1;    /* esign=0 if the exponent is < 0 */
  2068.     
  2069.     
  2070.     is[0]=fs[0]=es[0]= '\0';
  2071.     while((*s==' ')||(*s=='\t')) s++;  
  2072.     
  2073.     switch (*s){
  2074.         case '-': sign = 0;
  2075.         case '+': s++;
  2076.     }
  2077.     
  2078.     if ((*s)&&(*s != '.')) s= _katof_fill(s,is);
  2079.     if (*s == '.') s= _katof_fill(++s,fs);
  2080.     if ((*s == 'e')||(*s == 'E')) {
  2081.         switch (*(++s)){
  2082.             case '-': esign = 0;
  2083.             case '+': s++;
  2084.         }
  2085.         s= _katof_fill(s,es);
  2086.     }
  2087.     ii= atoi_d(is);
  2088.     fi= atoi_d(fs);
  2089.     ei= esign ? atoi(es) : -atoi(es);
  2090.     
  2091.     efac=1.0;
  2092.     if (ei>0) for(;ei;ei--) efac *= 10.0;    /* Clumsey. But this is just a make-do function. */
  2093.     if (ei<0) for(;ei;ei++) efac /= 10.0;    /* Ditto. */
  2094.     
  2095.     flen= strlen(fs);
  2096.     while(flen--) fi /= 10.0;        /* Ditto. */
  2097.     
  2098.     if (!sign) efac = -efac;
  2099.     return ( (ii + fi) * efac );
  2100. }
  2101.  
  2102. double atoi_d(s)
  2103. char *s;
  2104. {
  2105.     double n=0.0;
  2106.     for (;*s;s++){
  2107.         n *= 10.0;
  2108.         n += *s - 48;
  2109.     }
  2110.     return(n);
  2111. }
  2112.  
  2113. char *_katof_fill(from,to)
  2114. char *from,*to;
  2115. {
  2116.     int count=0;
  2117.     
  2118.     while((*from>='0')&&(*from<='9')&&(++count<_STRTODLEN_)) 
  2119.         (*to++)=(*from++);
  2120.     *to=0;
  2121.     return(from);
  2122. }
  2123. void mem_full(n)
  2124. int n;
  2125. {
  2126.     int c;
  2127.     
  2128.     if (autoexit){
  2129.         ng_help(5);
  2130.         exitt(3);
  2131.     }
  2132.     while(n%8) free( pdata[--n] );
  2133.     xwidth=xlimit=n;
  2134.     aspect= (double)ylimit/(double)xlimit;
  2135.     wsize= ( (double)xlimit*(double)ylimit )/AREA;
  2136.  
  2137.     printf("\007\
  2138. *** Insufficient memory. ***\n\
  2139. *** Reducing frame size. ***\n\
  2140.     New size = %g New aspect ratio = %g\n\n\
  2141.     (P)rocede or (A)bort? ",wsize,aspect);
  2142.     
  2143.     for(;;){
  2144.         switch( c=inkey() ){
  2145.             case 'a':
  2146.             case 'A':
  2147.                 while(--n>=0) free(pdata[n]);
  2148.                 free(virtscreen);
  2149.                 ng_help(3);
  2150.                 exitt(3);
  2151.             case 'p':
  2152.             case 'P': return;
  2153.             case 0:   break;
  2154.             default: putchar(c);
  2155.         }
  2156.     }
  2157. }
  2158. double dsqroot(n)
  2159. double n;
  2160. {
  2161.     double r1,r2;
  2162.     r1=n=n*1000000.0;
  2163.     r2=1.0;
  2164.  
  2165.     while (r1>r2+0.00001){
  2166.         r1=(r1+r2)/2.0;
  2167.         r2=n/r1;
  2168.     }
  2169.     return(r1/1000.0);
  2170. }
  2171. void ng_help(q)
  2172. int q;
  2173. {
  2174.     static char *mp[6] = {
  2175.         "",
  2176.         "\n*** Incorrect number of arguments.\n",
  2177.         "\n*** No RAM available.\n",
  2178.         " Aborted at user request.\n",
  2179.         "\n*** Size/aspect error.\n",
  2180.         "\n*** Insufficient memory.\n"
  2181.     };
  2182.     
  2183.     printf("%s\n%s%s.\n%s%s\nSee MANDEL.DOC for instructions.\n",mp[q],_help[0],version,cpyr,_help[1]);
  2184. }
  2185. hline(v,h1,h2)   /* v is offset of screen line. 
  2186.         h1 and h2 are character position, not pixel number. */
  2187. int v,h1,h2;
  2188. {
  2189.     
  2190.     for(;h1<=h2;h1++)
  2191.         screen1[v+h1] = 0xff;
  2192. }
  2193. vline(v1,v2,h)   /* v1 and v2 are vertical pixel numbers.
  2194.         h is character number, not pixel number. */
  2195. int v1,v2,h;
  2196. {
  2197.     
  2198.     for(;v1<=v2;v1++)
  2199.         screen1[0x2000 * (v1&3) + 90*(v1>>2) +h]= 24;
  2200. }
  2201.